package com.cmcc.migu.cmmon.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * ftp连接管理类
 * </p>
 */
public class FtpClientUtil {
	private FTPClient ftpClient = null;
	private String server;
	private int port;
	private String userName;
	private String userPassword;

	Logger logger = LoggerFactory.getLogger(FtpClientUtil.class);

	public FtpClientUtil(String server, int port, String userName, String userPassword) {
		this.server = server;
		this.port = port;
		this.userName = userName;
		this.userPassword = userPassword;
	}

	public FtpClientUtil() {
	}

	/**
	 * 链接到服务器
	 *
	 * @return
	 * @throws Exception
	 */
	public boolean open() {
		if (ftpClient != null && ftpClient.isConnected()) {
			return true;
		}
		try {
			ftpClient = new FTPClient();
			// 连接
			ftpClient.connect(this.server, this.port);
			ftpClient.login(this.userName, this.userPassword);
			// 检测连接是否成功
			int reply = ftpClient.getReplyCode();
			if (!FTPReply.isPositiveCompletion(reply)) {
				this.close();
				System.err.println("FTP server refused connection.");
				System.exit(1);
			}
			System.out.println("open FTP success:" + this.server + ";port:" + this.port + ";name:" + this.userName + ";pwd:" + this.userPassword);
			ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); // 设置上传模式.binally
			return true;
		} catch (Exception ex) {
			// 关闭
			this.close();
			ex.printStackTrace();
			return false;
		}

	}

	/**
	 * Description: 向FTP服务器上传文件
	 * 
	 * @Version1.0
	 * @param url
	 *            FTP服务器hostname
	 * @param port
	 *            FTP服务器端口
	 * @param username
	 *            FTP登录账号
	 * @param password
	 *            FTP登录密码
	 * @param path
	 *            FTP服务器保存目录
	 * @param filename
	 *            上传到FTP服务器上的文件名
	 * @param input
	 *            输入流
	 * @return 成功返回true，否则返回false
	 */
	public boolean uploadFile(String path, String filename, InputStream input) {
		boolean retFlag = false;
		if (!ftpClient.isConnected()) {
			return false;
		}
		try {
			ftpClient.enterLocalPassiveMode();
			ftpClient.setControlEncoding("UTF-8");
			ftpClient.changeWorkingDirectory(path);
			 try {
	                ftpClient.sendCommand("dele " + filename + "\r\n");  
	            } catch (Exception e) {  
	                System.out.println("删除文件失败！请检查系统FTP设置,并确认FTP服务启动");  
	            }  
			retFlag = ftpClient.storeFile(new String(filename.getBytes("UTF-8"),"iso-8859-1"), input);
			input.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return retFlag;
	}
	

	@SuppressWarnings("unused")
	private boolean cd(String dir) throws IOException {
		if (ftpClient.changeWorkingDirectory(dir)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 获取目录下所有的文件名称
	 *
	 * @param filePath
	 * @return
	 * @throws IOException
	 */

	@SuppressWarnings("unused")
	private FTPFile[] getFileList(String filePath) throws IOException {
		FTPFile[] list = ftpClient.listFiles();
		return list;

	}

	/**
	 * 循环将设置工作目录
	 */
	public boolean changeDir(String ftpPath) {
		if (!ftpClient.isConnected()) {
			return false;
		}
		try {

			// 将路径中的斜杠统一
			char[] chars = ftpPath.toCharArray();
			StringBuffer sbStr = new StringBuffer(256);
			for (int i = 0; i < chars.length; i++) {

				if ('\\' == chars[i]) {
					sbStr.append('/');
				} else {
					sbStr.append(chars[i]);
				}
			}
			ftpPath = sbStr.toString();
			// System.out.println("ftpPath"+ftpPath);

			if (ftpPath.indexOf('/') == -1) {
				// 只有一层目录
				// System.out.println("change"+ftpPath);
				ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(), "iso-8859-1"));
			} else {
				// 多层目录循环创建
				String[] paths = ftpPath.split("/");
				// String pathTemp = "";
				for (int i = 0; i < paths.length; i++) {
					// System.out.println("change "+paths[i]);
					ftpClient.changeWorkingDirectory(new String(paths[i].getBytes(), "iso-8859-1"));
				}
			}

			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 循环创建目录，并且创建完目录后，设置工作目录为当前创建的目录下
	 */
	public boolean mkDir(String ftpPath) {
		if (!ftpClient.isConnected()) {
			return false;
		}
		try {

			// 将路径中的斜杠统一
			char[] chars = ftpPath.toCharArray();
			StringBuffer sbStr = new StringBuffer(256);
			for (int i = 0; i < chars.length; i++) {

				if ('\\' == chars[i]) {
					sbStr.append('/');
				} else {
					sbStr.append(chars[i]);
				}
			}
			ftpPath = sbStr.toString();
			System.out.println("ftpPath" + ftpPath);

			if (ftpPath.indexOf('/') == -1) {
				// 只有一层目录

				ftpClient.makeDirectory(new String(ftpPath.getBytes(), "iso-8859-1"));
				ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(), "iso-8859-1"));
			} else {
				// 多层目录循环创建
				String[] paths = ftpPath.split("/");
				// String pathTemp = "";
				for (int i = 0; i < paths.length; i++) {

					ftpClient.makeDirectory(new String(paths[i].getBytes(), "iso-8859-1"));
					ftpClient.changeWorkingDirectory(new String(paths[i].getBytes(), "iso-8859-1"));
				}
			}

			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 上传文件到FTP服务器
	 *
	 * @param localPathAndFileName
	 *            本地文件目录和文件名
	 * @param ftpFileName
	 *            上传后的文件名
	 * @param ftpDirectory
	 *            FTP目录如:/path1/pathb2/,如果目录不存在回自动创建目录
	 * @throws Exception
	 */
	public boolean put(String localDirectoryAndFileName, String ftpFileName, String ftpDirectory) {
		if (!ftpClient.isConnected()) {
			return false;
		}
		boolean flag = false;
		if (ftpClient != null) {
			File srcFile = new File(localDirectoryAndFileName);
			FileInputStream fis = null;
			try {
				fis = new FileInputStream(srcFile);

				// 创建目录

				this.mkDir(ftpDirectory);

				ftpClient.setBufferSize(1024);
				ftpClient.setControlEncoding("UTF-8");

				// 设置文件类型（二进制）
				ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
				// 上传
				flag = ftpClient.storeFile(new String(ftpFileName.getBytes(), "iso-8859-1"), fis);
			} catch (Exception e) {
				this.close();
				e.printStackTrace();
				return false;
			} finally {
				IOUtils.closeQuietly(fis);
			}
		}

		System.out.println("success put file " + localDirectoryAndFileName + " to " + ftpDirectory + ftpFileName);
		return flag;
	}

	/**
	 * 从FTP服务器上下载文件并返回下载文件长度
	 *
	 * @param ftpDirectoryAndFileName
	 * @param localDirectoryAndFileName
	 * @return
	 * @throws Exception
	 */
	public long get(String ftpDirectoryAndFileName, String localDirectoryAndFileName) {
		long result = 0;
		if (!ftpClient.isConnected()) {
			return 0;
		}
		ftpClient.enterLocalPassiveMode(); // Use passive mode as default
		// because most of us are behind
		// firewalls these days.

		try {
			// 将路径中的斜杠统一
			char[] chars = ftpDirectoryAndFileName.toCharArray();
			StringBuffer sbStr = new StringBuffer(256);
			for (int i = 0; i < chars.length; i++) {

				if ('\\' == chars[i]) {
					sbStr.append('/');
				} else {
					sbStr.append(chars[i]);
				}
			}
			ftpDirectoryAndFileName = sbStr.toString();
			String filePath = ftpDirectoryAndFileName.substring(0, ftpDirectoryAndFileName.lastIndexOf("/"));
			String fileName = ftpDirectoryAndFileName.substring(ftpDirectoryAndFileName.lastIndexOf("/") + 1);

			System.out.println("filePath | " + filePath);
			System.out.println("fileName | " + fileName);
			this.changeDir(filePath);
			OutputStream is = new FileOutputStream(localDirectoryAndFileName);
			if (is != null){
				ftpClient.retrieveFile(new String(fileName.getBytes(), "iso-8859-1"), is); // download
			}
			// file
			System.out.print(ftpClient.getReplyString()); // check result

		} catch (IOException e) {
			e.printStackTrace();
		}
		logger.info("Success get file" + ftpDirectoryAndFileName + " from " + localDirectoryAndFileName);
		return result;
	}

	/**
	 * 只能读取小文件 内容 请勿读取大文件
	 * 
	 * @param ftpDirectoryAndFileName
	 * @return
	 */
	public String getFileContent(String ftpDirectoryAndFileName) {
		OutputStream is = new ByteArrayOutputStream();
		return getFileOutputStream(ftpDirectoryAndFileName, is) == null ? "" : getFileOutputStream(ftpDirectoryAndFileName, is).toString();
		// return null;
	}

	public OutputStream getFileOutputStream(String ftpDirectoryAndFileName, OutputStream is) {
		if (!ftpClient.isConnected()) {
			return null;
		}
		ftpClient.enterLocalPassiveMode(); // Use passive mode as default

		try {
			// 将路径中的斜杠统一
			char[] chars = ftpDirectoryAndFileName.toCharArray();
			StringBuffer sbStr = new StringBuffer(256);
			for (int i = 0; i < chars.length; i++) {

				if ('\\' == chars[i]) {
					sbStr.append('/');
				} else {
					sbStr.append(chars[i]);
				}
			}
			ftpDirectoryAndFileName = sbStr.toString();
			String filePath = ftpDirectoryAndFileName.substring(0, ftpDirectoryAndFileName.lastIndexOf("/"));
			String fileName = ftpDirectoryAndFileName.substring(ftpDirectoryAndFileName.lastIndexOf("/") + 1);

			System.out.println("filePath | " + filePath);
			System.out.println("fileName | " + fileName);
			this.changeDir(filePath);

			ftpClient.retrieveFile(new String(fileName.getBytes(), "iso-8859-1"), is); // download
			return is;

		} catch (IOException e) {
			e.printStackTrace();
		}

		return null;
	}

	public void getFileOutputStream(String path, String fileName, OutputStream is) {
		if (!ftpClient.isConnected()) {
			return;
		}
		ftpClient.enterLocalPassiveMode(); // Use passive mode as default
		try {
			this.changeDir(path);
			System.out.println(is.toString());
			ftpClient.retrieveFile(new String(fileName.getBytes(), "iso-8859-1"), is); // download
			System.out.println(is.toString());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 上传文件到FTP服务器，支持断点续传
	 * 
	 * @param local
	 *            本地文件名称，绝对路径
	 * @param remote
	 *            远程文件路径，使用/home/directory1/subdirectory/file.ext
	 *            按照Linux上的路径指定方式，支持多级目录嵌套，支持递归创建不存在的目录结构
	 * @return 上传结果
	 * @throws IOException
	 */
	@SuppressWarnings("resource")
	public String upload(String local, String remote) throws IOException {
		// 设置PassiveMode传输
		ftpClient.enterLocalPassiveMode();
		// 设置以二进制流的方式传输
		ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
		String result = "false";
		// 对远程目录的处理
		String remoteFileName = remote;
		String directory = "";
		if (remote.contains("/")) {
			remoteFileName = remote.substring(remote.lastIndexOf("/") + 1);
			directory = remote.substring(0, remote.lastIndexOf("/"));
//			ftpClient.changeWorkingDirectory(directory);
		}
		// 检查远程是否存在文件
		FTPFile[] files = ftpClient.listFiles("/"+directory);
		if (files.length == 1) {
			long remoteSize = files[0].getSize();
			File f = new File(local);
			long localSize = f.length();
			if (remoteSize == localSize) {
				return "ContinueFTP.File_Exits";
			} else if (remoteSize > localSize) {
				return "ContinueFTP.Remote_Bigger_Local";
			}

			// 尝试移动文件内读取指针,实现断点续传
			InputStream is = new FileInputStream(f);
			if (is.skip(remoteSize) == remoteSize) {
				ftpClient.setRestartOffset(remoteSize);
				if (ftpClient.storeFile(remote, is)) {
					return "ContinueFTP.Upload_From_Break_Success";
				}else{
					result =  "ContinueFTP.Upload_From_Break_Error";
				}
			}

			// 如果断点续传没有成功，则删除服务器上文件，重新上传
			if (!ftpClient.deleteFile(remoteFileName)) {
				return "ContinueFTP.Delete_Remote_Faild";
			}
			is = new FileInputStream(f);
			if (ftpClient.storeFile(remote, is)) {
				result = "Upload_New_File_Success";
			} else {
				result = "Upload_New_File_Failed";
			}
			is.close();
		} else {
			InputStream is = new FileInputStream(local);
			if (ftpClient.storeFile(remoteFileName, is)) {
				result = "ContinueFTP.Upload_New_File_Success";
			} else {
				result = "ContinueFTP.Upload_New_File_Failed";
			}
			is.close();
			
		}
		return result;
	}

	/**
	 * 返回FTP目录下的文件列表
	 *
	 * @param ftpDirectory
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public List getFileNameList(String ftpDirectory) {
		List list = new ArrayList();
		// if (!open())
		// return list;
		// try {
		// DataInputStream dis = new DataInputStream(ftpClient
		// .nameList(ftpDirectory));
		// String filename = "";
		// while ((filename = dis.readLine()) != null) {
		// list.add(filename);
		// }
		// } catch (Exception e) {
		// e.printStackTrace();
		// }
		return list;
	}

	/**
	 * 删除FTP目录
	 *
	 * @param ftpDirectory
	 */
	public boolean deleteDirectory(String ftpDirectory) {
		if (!ftpClient.isConnected()) {
			return false;
		}
		// ToDo
		return true;
	}

	/**
	 * 关闭链接
	 */
	public void close() {
		try {
			if (ftpClient != null && ftpClient.isConnected())
				ftpClient.disconnect();
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("Close Server Success :" + this.server + ";port:" + this.port);
	}

	public FTPClient getFtpClient() {
		return ftpClient;
	}

	public void setFtpClient(FTPClient ftpClient) {

		this.ftpClient = ftpClient;
	}

}
